package me.duzhi.ilog.cms.controller;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.jfinal.aop.Before;
import com.jfinal.ext.interceptor.POST;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.jfinal.render.Render;
import com.jfinal.render.RenderException;
import io.jpress.core.JBaseController;
import io.jpress.interceptor.InterUtils;
import io.jpress.message.MessageKit;
import io.jpress.model.Content;
import io.jpress.model.Metadata;
import io.jpress.model.User;
import io.jpress.model.query.ContentQuery;
import io.jpress.model.query.MetaDataQuery;
import io.jpress.router.RouterMapping;
import io.jpress.utils.StringUtils;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import me.duzhi.ilog.cms.function.Functions;
import me.duzhi.ilog.cms.plugins.history.HistoryListener;
import me.duzhi.ilog.cms.searcher.LuceneSearcher;

/**
 * @author ashang.peng@aliyun.com
 * @date 十二月 09, 2016
 */
@RouterMapping(url = "/to_all")
public class HelperController extends JBaseController {

  public static final Log log = Log.getLog(HelperController.class);

  public static final Map<String, Integer> finalStar = new HashMap();

  static {
    finalStar.put("starthree", 3);
    finalStar.put("startwo", 2);
    finalStar.put("starone", 1);
    finalStar.put("starfive", 5);
    finalStar.put("starfour", 4);
  }


  public void url() {
    String type = getPara(0);
    BigInteger pid = getParaToBigInteger(1);
    Content content = ContentQuery.me().findById(pid);
    String source = content.getMetadata("source");
    if (StringUtils.isNotBlank(source)) {
      redirect(source, true);
    }

  }

  public void ip() {
    System.out.println("header params");
    Enumeration hnames = getRequest().getHeaderNames();
    for (Enumeration e = hnames; e.hasMoreElements(); ) {
      String thisName = e.nextElement().toString();
      String thisValue = getRequest().getHeader(thisName);
      System.out.println(thisName + "-------" + thisValue);
    }
    System.out.println("request params:");
    Enumeration rnames = getRequest().getParameterNames();
    for (Enumeration e = rnames; e.hasMoreElements(); ) {
      String thisName = e.nextElement().toString();
      String thisValue = getRequest().getParameter(thisName);
      System.out.println(thisName + "-------" + thisValue);
    }
    MessageKit.sendMessage(HistoryListener.ACTION_LOAD_HISTORY);
    renderAjaxResultForError();
  }

  @Before(POST.class)
  public void ajax() {
    String action = getPara("action");
    if ("rating".equals(action)) {
      int pid = getParaToInt("pid");
      BigInteger id = BigInteger.valueOf(pid);
      String sid = getPara("sid");
      Functions.setMetaData(id, sid);
    } else if ("like".equals(action)) {
      int pid = getParaToInt("pid");
      User user = InterUtils.tryToGetUser(this);
      Functions.like(BigInteger.valueOf(pid), user);
    }
    renderAjaxResult("ok", 0);
  }

  private void setMetaData(BigInteger id, String sid) {
    String ratesdes = "ratesdes";//描述
    String ratingCount = "ratingCount";//总数
    String ratingValue = "ratingValue";//平均值
    Metadata metadata = MetaDataQuery.me().findByTypeAndIdAndKey("content", id, "ratingValue");
    float _ratingValue = new Float(metadata.getMetaValue());
    _ratingValue = (_ratingValue + finalStar.get(sid)) / 2;
    DecimalFormat fnum = new DecimalFormat("##0");
    String _ratesdes = fnum.format(_ratingValue);

    if (metadata == null) {
      metadata = new Metadata();
      metadata.setMetaKey("ratingValue");
      metadata.setMetaValue(String.valueOf(finalStar.get(sid)));
    } else {
      metadata.setMetaValue(String.valueOf(_ratingValue));
    }
  }

  public void reloadLucene() {
    String createIndexSearcher = getPara("createIndexSearcher");
    if ("10bf8b728e72ae7c496512ef15eff9b08adb7d118eaa32e3c3a01c38f4c4dc69"
        .equals(createIndexSearcher)) {
      LuceneSearcher.reloadIndex();
    }
    renderAjaxResultForSuccess();
  }

  public void qrCode() {
    String msg = getPara("data", "");
    Integer width = getParaToInt("width", 200);
    Integer height = getParaToInt("height", 200);
    render(new QrCodeRender(msg, width, height, 'H'));
  }

  public class QrCodeRender extends Render {

    private String content;
    private int width;
    private int height;
    private ErrorCorrectionLevel errorCorrectionLevel;

    /**
     * 构造方法，经测试不指定纠错参数时，默认使用的是 'L' 最低级别纠错参数
     *
     * @param content 二维码携带内容
     * @param width 二维码宽度
     * @param height 二维码高度
     */
    public QrCodeRender(String content, int width, int height) {
      init(content, width, height, null);
    }

    /**
     * 带有纠错级别参数的构造方法，生成带有 logo 的二维码采用纠错原理
     * 使用 ErrorCorrectionLevel.H 参数提升纠错能力
     *
     * ErrorCorrectionLevel 是枚举类型，纠错能力从高到低共有四个级别：
     * H = ~30% correction
     * Q = ~25% correction
     * M = ~15% correction
     * L = ~7%
     *
     * 使用的时候直接这样：ErrorCorrectionLevel.H
     */
    public QrCodeRender(String content, int width, int height,
        ErrorCorrectionLevel errorCorrectionLevel) {
      init(content, width, height, errorCorrectionLevel);
    }

    /**
     * 带有纠错级别参数的构造方法，纠错能力从高到低共有四个级别：'H'、'Q'、'M'、'L'
     */
    public QrCodeRender(String content, int width, int height, char errorCorrectionLevel) {
      init(content, width, height, errorCorrectionLevel);
    }

    private void init(String content, int width, int height, char errorCorrectionLevel) {
      if (errorCorrectionLevel == 'H') {
        init(content, width, height, ErrorCorrectionLevel.H);
      } else if (errorCorrectionLevel == 'Q') {
        init(content, width, height, ErrorCorrectionLevel.Q);
      } else if (errorCorrectionLevel == 'M') {
        init(content, width, height, ErrorCorrectionLevel.M);
      } else if (errorCorrectionLevel == 'L') {
        init(content, width, height, ErrorCorrectionLevel.L);
      } else {
        throw new IllegalArgumentException("errorCorrectionLevel 纠错级别参数值，从高到低必须为： 'H'、'Q'、'M'、'L'");
      }
    }

    private void init(String content, int width, int height,
        ErrorCorrectionLevel errorCorrectionLevel) {
      if (StrKit.isBlank(content)) {
        throw new IllegalArgumentException("content 不能为空");
      }
      if (width < 0 || height < 0) {
        throw new IllegalArgumentException("width 与 height 不能小于 0");
      }
      this.content = content;
      this.width = width;
      this.height = height;
      this.errorCorrectionLevel = errorCorrectionLevel;
    }

    public void render() {
      response.setDateHeader("Expires", 600000);
      response.addHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
      response.setContentType("image/png");

      Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
      hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
      hints.put(EncodeHintType.MARGIN, 0);    //去掉白色边框，极度重要，否则二维码周围的白边会很宽
      if (errorCorrectionLevel != null) {
        hints.put(EncodeHintType.ERROR_CORRECTION, errorCorrectionLevel);
      }

      try {
        // MultiFormatWriter 可支持多种格式的条形码，在此直接使用 QRCodeWriter，通过查看源码可知少创建一个对象
        // BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);

        QRCodeWriter writer = new QRCodeWriter();
        BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);

        // 经测试 200 X 200 大小的二维码使用 "png" 格式只有 412B，而 "jpg" 却达到 15KB
        MatrixToImageWriter
            .writeToStream(bitMatrix, "png", response.getOutputStream());    // format: "jpg"、"png"
      } catch (Exception e) {
        throw new RenderException(e);
      }
    }
  }
}
